using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace PrivateEngine
{
	
	public class Loop_Item
	{
		public string address;	
		public int loop_start, loop_end;
		public List<int> statements;
		public List<string> loop_private_var;
		public bool check;
		public bool parallel;
		public int level;
		
		public Loop_Item(string _prefix)
		{
			address = _prefix;	
			statements = new List<int>();
			loop_private_var = new List<string>();
			check = true;
			parallel = false;
		}
		
		public void print()
		{
			Console.WriteLine("Loop " + address + " lines: " + loop_start + " " + loop_end);
			Console.Write("statements: ");
			foreach(int z in statements)
				Console.Write(z.ToString() + ", ");
			Console.WriteLine();
			Console.Write("private: ");
			foreach(string zz in loop_private_var)
				Console.Write(zz + ", ");
			Console.WriteLine();
			
		}
		
		public void Add_index(string invar)  //dodawaj bez powtorzen zmienne indeksowe
		{
			bool _add = true;
			foreach(string zz in loop_private_var)
				if(zz == invar)
					_add = false;
			
			if(_add)
				loop_private_var.Add(invar);
			
		}
		
		public string get_vars()
		{
			string tmp = "";
			
			foreach(string zz in loop_private_var)
				tmp += zz + ", ";
			
			tmp = tmp.Substring(0, tmp.Length-2);
			
			return tmp;
				
		}
	}
	
	public class ParseTree
	{
		public string loop_file;

		
		public List<Loop_Item> All_Loops = new List<Loop_Item>();
		
		
		
		
		public ParseTree (string lf)
		{
			loop_file = lf;
		//	tmp_folder = "/home/marek/tmp/";
			

		}
		
		private string GetParentPrefix(string prefix)
		{
			if(prefix.LastIndexOf(";")-1 > 0)
			prefix = prefix.Substring(0, prefix.LastIndexOf(";")-1);
			else prefix = "";
			return prefix;						
		}
			                          
		private Loop_Item LoopSearch(string prefix)
		{
			foreach(Loop_Item l in All_Loops)
				if(l.address == prefix)
					return l;
			return null;
		}
		
		public void ReadParseTree()
		{
			string line;
			int current_level = 0;
			List <int> state_counter = new List<int>();
			string prefix = "";
			
			int line_counter = 0;
			
			StreamReader file = new StreamReader(loop_file);
			while((line = file.ReadLine()) != null)
			{
				line_counter++;
				if(current_level == 0 && !(line.Contains("for") && line.Contains("do")))
					continue;
				
				if(line.Contains("endfor"))
				{
						LoopSearch(prefix).loop_end = line_counter;

						current_level--;
						//prefix = prefix.Substring(0, prefix.Length-2);  // o liczby udoskonalic
						prefix = GetParentPrefix(prefix);
					

					
					if(prefix == "")
						break; //koniec petli
					continue;					
				}
				
				else if(line.Contains("for") && line.Contains("do"))  // petla
				{
					current_level++;
					
					if(current_level > state_counter.Count) //pierwsza petla na tym poziomie
						state_counter.Add(1);
					else
						state_counter[current_level-1] = state_counter[current_level-1] + 1;
					
									
					prefix += state_counter[current_level-1].ToString() + ";";
					
					//Console.WriteLine(line_counter.ToString() + " loop " + prefix);
					
					//Console.WriteLine(GetParentPrefix(prefix));

					Loop_Item item = new Loop_Item(prefix);
					item.loop_start = line_counter;
					All_Loops.Add(item);
					
					string index = line.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries)[1];
					index = index.Substring(0, index.IndexOf('='));
					
					item.Add_index(index);
					item.level = current_level;
					
					string _pf = prefix;
					// instrukcja dodaj do petli i jej przodkow	
					do{
						LoopSearch(_pf).Add_index(index);
					}
					while((_pf = GetParentPrefix(_pf)) != "");
					

					
				}
				else
				{
					string _pf = prefix;
					// instrukcja dodaj do petli i jej przodkow	
					do{
						LoopSearch(_pf).statements.Add(line_counter);
					}
					while((_pf = GetParentPrefix(_pf)) != "");
				}
									
				
			}
			
			file.Close();
			
			foreach(Loop_Item l in All_Loops)
			{
				l.print();				
			}
			
			
		}
	
		public void Parallelize(string deps_file)
		{
			PrivateAlg pe = new PrivateAlg();
			pe.deps_file = deps_file;
			
			foreach(Loop_Item _loop in All_Loops)
			{
				if(_loop.check)
				{
				//try to privatize
					if(pe.Privatizing(_loop) == "OK")
					{
						_loop.parallel = true;
						
						//do not analyze internal loops
						foreach(Loop_Item _tmp in All_Loops)	
							if(_tmp.address.StartsWith(_loop.address) && _tmp.address != _loop.address)
							{
									_tmp.check = false;
									_tmp.parallel = false;
							}

						
						
					}
					else
						_loop.parallel = false;
				}
				
			}
			
		}
		
		public void GenerateCode(string output_file)
		{
			StreamReader file = new StreamReader(loop_file);
			StreamWriter outfile = new StreamWriter(output_file);
			int line_counter = 0;
			string line;
			
			while((line = file.ReadLine()) != null)
			{
				line_counter++;
				
				if(line.Contains("for") && line.Contains("do"))
				{
					foreach(Loop_Item l in All_Loops)
					{
						if(l.loop_start == line_counter && l.parallel)
						{
							outfile.WriteLine("# parallel for private(" + l.get_vars() + ")");								
						}
							
						
					}
				}
				
				outfile.WriteLine(line);
			}
			
			file.Close();
			outfile.Close();
			
		}
	
	}
}

